#include "DirectLOL/gameEngine/gameEngine.h"
#include <fstream>
#include <iostream>
#include <sstream>

GameEngine::GameEngine()
{
    clearColor= new Vectorf(0.0, 0.0, 0.0, 1.0);

    projection=new Ortho();
    viewpoint= new ViewPoint3D();

    frameCount=0;
    lastTime=0;
    continuer=1;
    frameRate=10;
    lightPosition= new float[4]{10.0, 10.0, 10.0, 1.0};

    events      =new EventManager();
    sdlwindow   =new SDLWindow();
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::DefineViewpoint(ViewPoint * aViewpoint)
{
    delete viewpoint;
    viewpoint=aViewpoint;
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::EraseCollision()
{
    for(int i=0;i<collisions.size();i++)
    {
        if(collisions.at(i)->end)
        {
            collisions.erase(collisions.begin()+i);
            i--;
        }
    }
}

/*-------------------------------------------------------------------------------------*/

int GameEngine::EndCollision(Collision *col)
{
    col->end=1;
    EraseCollision();
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::GameLoop()
{
    while(continuer)
    {
        /*! Méthode permettant de connaitre à quel instant t se trouve le programme depuis son exécution*/

        currentTime=SDL_GetTicks();

        /*! Dans le cas ou x ou plus de ms se sont écoulés depuis le dernier rafraichissement (ou x = framerate
            on rafraichit l'image    */

        if(currentTime-lastTime>=frameRate)
        {
            lastTime=currentTime;
            frameCount++;

            ResolveEvents();        /*! Gestion de tout les événements */
            UpdatePhysic();         /*! Mise à jour de la position des éléments */
            UpdateCollisions();     /*! Gestion des collisions */
            UpdatePositions();      /*! position = position +1 , validation de la position future de l'objet (pas de collisions ) */

            DisplayFrame();

            SDL_GL_SwapBuffers();
        }
        else /*! Autrement, on endort le programme jusqu'à atteindre la valeur temporelle souhaité */
        {
            SDL_Delay(frameRate - (currentTime - lastTime));
        }
    }
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::DisplayFrame()
{
    glMatrixMode(GL_MODELVIEW);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();

    viewpoint->Use();



    for(int i=0;i<elements.size();i++)
    {
         glLightfv (GL_LIGHT0, GL_POSITION, lightPosition);
        elements.at(i)->Display();
    }
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::InitSDL(int aWidth, int aHeight)
{
    sdlwindow->InitWindow(aWidth,aHeight);
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::UpdateCollisions()
{
    for(int i=0;i<collisions.size();i++)
    {
        collisions.at(i)->Update();
    }
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::UpdatePhysic()
{
    for(int i=0;i<elements.size();i++)
    {
        if(elements.at(i)->physicOn==1)
        {
            elements.at(i)->ResolvePhysic();
        }
    }
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::ResolveEvents()
{
    events->CheckEvents();
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::InitGL()
{
    glewInit();
    glClearDepth(1);
    glClearColor(clearColor->x(),clearColor->y(),clearColor->z(),clearColor->w());

    glEnable(GL_DEPTH_BUFFER);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_COLOR_MATERIAL);

    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

    glEnable(GL_NORMALIZE);

    glEnable(GL_TEXTURE_2D);

  //  glEnable(GL_CULL_FACE);

    glDepthFunc(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

   // glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   // glFrontFace(GL_CW);
 //   glCullFace(GL_FRONT);


 //   glEnable(GL_CULL_FACE);
    //glDisable(GL_DEPTH_TEST);   // Active le Z-Buffer
    //glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
   // glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


   // glFrontFace(GL_CCW);
  //  glCullFace(GL_FRONT);

   // glEnable(GL_LIGHTING);
   // glEnable(GL_LIGHT0);


    projection->DefineProjection();
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::AddEvent(AbstractDelegate *aEvent)
{
    events->AddEvent(aEvent);
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::AddElement(GraphicElement * aObject)
{
    elements.push_back(aObject);
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::UpdatePositions()
{
    for(int i=0;i<elements.size();i++)
    {
        *(elements.at(i)->translation)=*(elements.at(i)->translationT1);
    }
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::DisplayPicking()
{
    glMatrixMode(GL_MODELVIEW);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    viewpoint->Use();

    for(int i=0;i<elements.size();i++)
    {
        elements[i]->Picking();
    }
}

/*-------------------------------------------------------------------------------------*/

void GameEngine::EraseElements()
{
    for(int i=0;i<elements.size();i++)
    {
        if(elements.at(i)->kill)
        {
            elements.erase(elements.begin()+i);
            i--;
        }
    }
}
